package com.toobigtofail
{
	import flash.net.getClassByAlias;
	
	import net.flashpunk.Entity;
	import net.flashpunk.FP;
	import net.flashpunk.graphics.Spritemap;
	import net.flashpunk.tweens.misc.NumTween;
	import net.flashpunk.utils.Ease;
	
	public class PlayerSection extends Entity
	{
		[Embed(source="/assets/gfx/player1.png")] private static const SNAKE1_PNG:Class;
		[Embed(source="/assets/gfx/player2.png")] private static const SNAKE2_PNG:Class;
		[Embed(source="/assets/gfx/player3.png")] private static const SNAKE3_PNG:Class;
		[Embed(source="/assets/gfx/player4.png")] private static const SNAKE4_PNG:Class;
		[Embed(source="/assets/gfx/player5.png")] private static const SNAKE5_PNG:Class;
		[Embed(source="/assets/gfx/player6.png")] private static const SNAKE6_PNG:Class;
		
		private static const SPACE_BETWEEN_SECTIONS:Number = -5;
		private static const VELOCITY_DIFF_MULTIPLIER:Number = 0.1;
		private static const MAX_SPACE_BETWEEN_SECTIONS:Number = 30;
		private static const MAX_IMAGE_ANGLE:Number = 30;
		
		private static const DEAD_FALL_ACCELERATION:Number = 0.2;
		
		private static const RIGHT_SET_SPEED:Number = 2;
		private static const RIGHT_SET_THRESHOLD:Number = 2;
		
		private var _snakeSprite1:Spritemap = new Spritemap(SNAKE1_PNG, 40, 20);
		private var _snakeSprite2:Spritemap = new Spritemap(SNAKE2_PNG, 40, 20);
		private var _snakeSprite3:Spritemap = new Spritemap(SNAKE3_PNG, 40, 20);
		private var _snakeSprite4:Spritemap = new Spritemap(SNAKE4_PNG, 40, 20);
		private var _snakeSprite5:Spritemap = new Spritemap(SNAKE5_PNG, 40, 20);
		private var _snakeSprite6:Spritemap = new Spritemap(SNAKE6_PNG, 40, 20);
		
		private var _snakeSpriteArray:Array = new Array(_snakeSprite1, _snakeSprite2, _snakeSprite3, _snakeSprite4, _snakeSprite5, _snakeSprite6);
		private var _snakeSprite:Spritemap;
		
		private var _state:String = "playing";
		
		
		
		public var nextSection:PlayerSection = null;
		public var previousSection:PlayerSection = null;
		public var peerID:String = null;
		
		public var color:uint = 0xFFFFFF;
		public var alpha:Number = 0.5;
		
		public var dy:Number = 0, dx:Number = 0;
		public var sectionNum:int = 0; // section 0 is the head
		
		public const ROTATE:NumTween = new NumTween;
		
		public function PlayerSection(x:Number=0, y:Number=0, nextSection:PlayerSection=null)
		{
			this.nextSection = nextSection;
			
			var pSection:PlayerSection = nextSection;
			while (null != pSection) {
				sectionNum++;
				pSection = pSection.nextSection;
			}
			_snakeSprite = _snakeSpriteArray[sectionNum];

			var frames:Array = new Array;
			var offset:int = (sectionNum%2 == 0 ? 0 : 6);
			for (var i:int = 0; i < 12; i++) {
				frames.push((i+offset)%12);
			}
			_snakeSprite.add("wiggle", frames, 12, true);
			

			width  = _snakeSprite.width;
			height = _snakeSprite.height;
			
			if (null != nextSection) {
				this.y = nextSection.y;
				this.x = nextSection.x - width - SPACE_BETWEEN_SECTIONS;
				nextSection.previousSection = this;
			} else {
				this.x = x;
				this.y = y;
			}
			

			//_snakeSprite.setFrame(5 - sectionNum, 0);
			_snakeSprite.alpha = alpha;
			graphic = _snakeSprite;
			
			addTween(ROTATE);
		}
		
		override public function update():void {
			super.update();
			
			switch (_state) {
				case "playing":
					_snakeSprite.alpha = alpha;
					_snakeSprite.play("wiggle");
					if (nextSection) {
						dy = dy < 0 ? Math.min(0, dy + Player.DECELERATION) : Math.max(0, dy - Player.DECELERATION);
						
						// Make sure the sections don't stray more than the max distance away
						var maxDiffY:Number = MAX_SPACE_BETWEEN_SECTIONS;
						var diffY:Number = nextSection.y - y;
						if (Math.abs(diffY) > maxDiffY) {
							y = nextSection.y - (diffY >= 0 ? 1 : -1) * maxDiffY;
							dy = nextSection.dy;
						}
						
						var absDiffY:Number = Math.abs(diffY);
						if (dy < RIGHT_SET_THRESHOLD && absDiffY > 0) {
							if (y < nextSection.y) {
								y += Math.min(RIGHT_SET_SPEED,absDiffY) ;
							} else {
								y -= Math.min(RIGHT_SET_SPEED,absDiffY);
							}
						}
						
						// set the angle of the image
						_snakeSprite.angle = FP.angle(x, y, nextSection.x, nextSection.y);
					} else {
						_snakeSprite.angle = MAX_IMAGE_ANGLE * -dy/Player.MAX_VELOCITY;
					}
					
					var oldY:Number = y;
					y += dy;
					
					if (y > FP.screen.height - height) {
						y = FP.screen.height - height;
					} else if (y < 0) {
						y = 0;
					}
					
					break;
				
				case "dead":
					_snakeSprite.angle = ROTATE.value;
					
					dy += DEAD_FALL_ACCELERATION;
					
					y += dy;
					x += dx;
					
					if (y > FP.screen.height - height) {
						y = FP.screen.height - height;
						dy = 0;
						dx = 0;
						
						_snakeSprite.angle = 0;
					}
					
					if (x < -width) {
						dx = 0;
					} else if (x > FP.screen.width) {
						dx = 0;
					}
					break;
			}
		}
		
		public function die():void {
			dx = Math.random()*10 - 5;
			dy = Math.random()*10 - 4;
			_state = "dead";
			
			ROTATE.tween(0, 360, (100-((Math.random()*100)%60))/100, Ease.quadInOut);
		}
		
		public function makeTiny():void {
			_snakeSprite.scale = 0.5;
			this.setHitbox(_snakeSprite.width * _snakeSprite.scale, _snakeSprite.height * _snakeSprite.scale);
			if (nextSection) {
				x = nextSection.x - width - SPACE_BETWEEN_SECTIONS;
			}
		}
		
		public function makeNormal():void {
			_snakeSprite.scale = 1;
			this.setHitbox(_snakeSprite.width * _snakeSprite.scale, _snakeSprite.height * _snakeSprite.scale);
			if (nextSection) {
				x = nextSection.x - width - SPACE_BETWEEN_SECTIONS;
			}
		}
		
		public function restart():void {
			dx = 0;
			dy = 0;
			_state = "playing";
			if (nextSection) {
				y = nextSection.y;
				x = nextSection.x - width - SPACE_BETWEEN_SECTIONS;
			}
		}
		
		public function get isDead():Boolean { return _state == "dead"; }
	}
}